package com.siyoumi.component;

import com.siyoumi.mybatispuls.EntityBase;
import com.siyoumi.exception.BaseExceptionHandler;
import com.siyoumi.util.XStr;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;

@Slf4j
public class XBean
        extends BeanUtils {
    /**
     * 获取对象，属性值
     *
     * @param target 对象
     * @param key    属性名
     * @return 值
     */
    static public Object getAttributeVal(Object target, String key) {
        PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(target.getClass(), key);
        if (propertyDescriptor == null) {
            return null;
        }

        Method readMethod = propertyDescriptor.getReadMethod();
        Object val = null;
        try {
            val = readMethod.invoke(target);
        } catch (Exception e) {
            log.error("KEY:{}", key);
            BaseExceptionHandler.printStackTrace(e);
        }
        return val;
    }

    /**
     * 设置对象属性值
     *
     * @param target 对象
     * @param key    属性名
     * @param val    设置值
     */
    static public void setAttributeVal(Object target, String key, Object val) {
        PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(target.getClass(), key);
        if (propertyDescriptor == null) {
            return;
        }

        if (val != null && val.getClass() == String.class) {
            //字符串转其他类型
            val = XStr.parseType((String) val, propertyDescriptor.getPropertyType(), null);
        }

        Method writeMethod = propertyDescriptor.getWriteMethod();
        try {
            writeMethod.invoke(target, val);
        } catch (Exception e) {
            log.error("KEY: {}", key);
            BaseExceptionHandler.printStackTrace(e);
        }
    }


    /**
     * 实例化对象
     *
     * @param class_c
     * @return 对象
     */
    static public <T> T newIns(Class<T> class_c) {
        return BeanUtils.instantiateClass(class_c);
    }


    static public Map<String, Object> toMap(Object entity) {
        return toMap(entity, null);
    }

    /**
     * 实体转map
     *
     * @param entity 实体
     * @return map
     */
    @SneakyThrows
    static public Map<String, Object> toMap(Object entity, List<String> ignoreField) {
        LinkedHashMap<String, Object> map = new LinkedHashMap<>();

        if (ignoreField == null) {
            ignoreField = new ArrayList<>();
        }
        ignoreField.add("autoID");
        ignoreField.add("class");

        PropertyDescriptor[] propertyDescriptors = XBean.getPropertyDescriptors(entity.getClass());
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            String keyName = propertyDescriptor.getName();
            if (ignoreField.contains(keyName)) {
                continue;
            }

            Method readMethod = propertyDescriptor.getReadMethod();
            //XLog.debug(XBean.class, keyName);
            Object v = null;
            if (readMethod != null) {
                readMethod.setAccessible(true);
                v = readMethod.invoke(entity);
            }

            map.put(keyName, v);
        }

        return map;
    }

    static public <T extends EntityBase<T>> Map<String, Object> toMap(T entity, String[] onlyFields) {
        if (entity == null) {
            return null;
        }

        Map<String, Object> mapData = new LinkedHashMap<>();
        Map<String, Object> mapEntity = entity.toMap();

        for (String field : onlyFields) {
            Object v = mapEntity.get(field);
            mapData.put(field, v);
        }

        return mapData;
    }


    @SneakyThrows
    static public <T> void fromMap(Map<String, Object> map, T entity) {
        String[] missKey = {
                "autoID",
                "class",
                "empty",
        };
        List<String> missKeyList = List.of(missKey);

        PropertyDescriptor[] propertyDescriptors = XBean.getPropertyDescriptors(entity.getClass());
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            String keyName = propertyDescriptor.getName();
            if (missKeyList.contains(keyName)) continue;

            Method writeMethod = propertyDescriptor.getWriteMethod();
            //log.debug(keyName);
            Object v = map.get(keyName);
            if (v != null && v.getClass() == String.class) {
                //字符串转其他类型
                v = XStr.parseType((String) v, propertyDescriptor.getPropertyType(), null);
            }

            if (writeMethod != null) {
                writeMethod.setAccessible(true);
                try {
                    writeMethod.invoke(entity, v);
                } catch (Exception ex) {
                    log.error(keyName);
                    throw ex;
                }

            }
        }
    }

    /**
     * 实体转map
     *
     * @param map 数字
     * @return map
     */
    @SneakyThrows
    static public <T> T fromMap(Map<String, Object> map, Class<T> clazz) {
        T entity = (T) XBean.newIns(clazz);
        fromMap(map, entity);

        return entity;
    }

    /**
     * 获取对象的类型
     *
     * @param classPath 类路径，例：com.siyoumi.component.api.send.robot.RobotErr
     * @return 类型，不存在返回null
     */
    static public <T> Class<T> getClassType(String classPath) {
        Class<T> classType = null;
        try {
            classType = (Class<T>) Class.forName(classPath);
        } catch (ClassNotFoundException e) {
            BaseExceptionHandler.printStackTrace(e);
        }

        return classType;
    }
}
